/* ResetRelationships.m created by cfeder on Thu 15-Dec-1994 */

#import "ResetRelationships.h"
#import "ValueForKey.h"
#import "RelationshipKeySetter.h"

@implementation EODatabaseChannel (setForeignKey)
- objectForPrimaryKey:(NSDictionary *)key entity:(EOEntity *)entity
    // returns existing object instance if there is one, or a fault otherwise
{
    EODatabaseContext *context = [self databaseContext];
    id object = [context objectForPrimaryKey:key entity:entity];
    if (!object) {
        object = [EOFault objectFaultWithPrimaryKey:key
            entity:entity databaseChannel:self zone:[self zone]];
    }
    return object;
}

- fetchObjectDescribedByQualifier:(EOQualifier *)qualifier
    // raises if not to-one.
{
    BOOL success, autoTransaction = NO;
    EODatabaseContext *context = [self databaseContext];
    NSZone *zone = [self zone];
    id object;

    if (![context transactionNestingLevel]) {
        [context beginTransaction];
        autoTransaction = YES;
    }

    success = [self selectObjectsDescribedByQualifier:qualifier
        fetchOrder:nil];
    object = [self fetchWithZone:zone];
    if (!success || !object || [self fetchWithZone:zone]) {
        [self cancelFetch];
        [NSException raise:NSInternalInconsistencyException format:@"%s: error fetching object", sel_getName(_cmd)];
    }

    if (autoTransaction) [context commitTransaction];
    return object;
}

- destinationObjectForRelationship:relationship sourceObject:sourceObject
    // look up an exising fault, or create a new one
{
    id object;
    // EODatabase *database = [[self databaseContext] database];

    if ([relationship isToMany]) {
        // EOF doesn't unique faults, so we just have to construct a new one
        EOQualifier *qual = [EOQualifier qualifierForObject:sourceObject relationship:relationship];
        object = [EOFault arrayFaultWithQualifier:qual
            fetchOrder:nil databaseChannel:self zone:[self zone]];
    } else {
        // see if this is already in the uniquing table
        if ([relationship isFlattened]) {
            EOQualifier *qual = [EOQualifier qualifierForObject:sourceObject relationship:relationship];

            // should fetch object from channel with qualifier
            object = [self fetchObjectDescribedByQualifier:qual];
        } else {
            // for to-ones, the primary key is always the destination of the
            // relationship
            NSDictionary *pk = [relationship destinationValuesFromSourceObject:sourceObject];
            object = [self objectForPrimaryKey:pk entity:[relationship destinationEntity]];
        }
    }
    return object;
}

- (void)updateRelationshipsInObject:object forModifiedAttributes:(NSArray *)attributes
   // After the values in object corresponding to the EOAttributes
   // in the "attributes" array have been update (perhaps with 
   // takeValuesFromDictionary) this method can be called to update any
   // corresponding relationship properties.  So, if a foreign dept_id
   // attribute way modified in a employee object, this would attempt to
   // reset the "toDepartment" property to point at the corresponding
   // department object.
{
    // We should apply some caching here to make this fast.  I.e. map directly
    // from attribute to list of class property relationships that this participates in.
    // For now we'll just be simple and slow.
    NSMutableArray *affectedRelationships = [NSMutableArray array];
    EOModel *model = [[[[self databaseContext] database] adaptor] model];
    EOEntity *entity = [model entityForObject:object];
    NSArray *classProperties = [entity classProperties];
    NSArray *relationships = [entity relationships];
    int i,count = [relationships count];

    for(i=0; i<count; i++) {
        EORelationship *relationship = [relationships objectAtIndex:i];

        if ([classProperties indexOfObjectIdenticalTo:relationship] != NSNotFound) {
            NSArray *joins = [relationship joins];
            int j, jcount = [joins count];

            for (j = 0; j < jcount; j++) {
                EOJoin *join = [joins objectAtIndex:j];
                if ([attributes indexOfObjectIdenticalTo:[join sourceAttribute]] != NSNotFound) {
                    [affectedRelationships addObject:relationship];
                    break;
                }
            }
        }
    }

    // We now have a list of affected relationships that we need to retarget
    {
        count = [affectedRelationships count];
        for(i=0; i<count; i++) {
            EORelationship *relationship = [relationships objectAtIndex:i];
            id dest = [self destinationObjectForRelationship:relationship sourceObject:object];
            [object takeValue:dest forKey:[relationship name]];
        }
    }
}
@end
